# coding=utf-8
import random
from .model.constants import Constants
from .model.expression import Expression
from .binary_tree import Tree
from .answer import Answer
from .model.config import Config
import json
# from app.common.mkdir import mk_time_dir
from app.common import mk_time_dir


def obj_2_json(obj):
    print(type(obj))
    return {
        "expression": obj.expression,
        "value": obj.value
    }


class Generator:
    """表达式生成类"""

    def __init__(self):
        # self.m = 0
        pass

    def format_expression(self, set_express, classname):
        print("***** start format expression *****")
        set_re = []
        right = 0
        wrong = 0
        if not set_express:
            return "空空如也"
        else:
            for i, exp in enumerate(set_express):
                # str1 = str(i) + ": " + exp.tostring()+"\n"
                # str2 = exp.tostring()
                print(type(exp))

                tem = {
                    'expression': exp.get_expression(),
                    'answer': str(exp.get_value())
                }
                # set_re.append(json.dumps(exp, default=lambda obj: obj.__dict__, sort_keys=True, indent=4))
                set_re.append(tem)
                # ans = input("第" + str(i+1) + "题: " + exp.get_expression() + "\n")
                # if ans == str(exp.get_value()):
                #     right = right + 1
                # else:
                #     wrong = wrong + 1
            # with open('expression.json', 'a+') as f:
            #     f.write(json.dumps(set_re))
            # mk_time_dir(set_re, classname)
            return set_re
            # print(str1)
            # return {
            #     "right": right,
            #     "wrong": wrong
            # }

    def generate(self, config):
        m = 0
        print("***** start generate expression *****")
        numofexp = config.numofexp
        set = []
        # randomNumberOfOperation 操作符随机数目

        for i in range(numofexp):
            random_number_of_operation = random.randint(1, config.maxnumofoper + 1)
            mark_fraction = 0
            if config.hasfraction:
                mark_fraction = random.randint(0, random_number_of_operation + 1) * 2

            # 操作数的数目 = 操作符的数目 + 1
            numberOfOpand = random_number_of_operation + 1
            exp = []
            for j in range(random_number_of_operation + numberOfOpand):
                if j % 2 == 0:
                    if j == mark_fraction and config.hasfraction:
                        exp.append(self.generator_oprand(True, config.myrange))
                    else:
                        exp.append(self.generator_oprand(self.random_flag(config.hasfraction), config.myrange))
                    if j > 1 and exp[j - 1] == Constants.DIVIDE and str(exp[j]) == Constants.ZERO:
                        # could not be ÷ 0 ,  generator operator from + - x
                        exp[j - 1] = self.pick_an_operation(self.generate_available_operators(
                            config.isHasMultipleAndDivide()))

                else:
                    exp.append(self.pick_an_operation(self.generate_available_operators(
                        config.isHasMultipleAndDivide())))

            expression = ""

            if config.hasparentheses and numberOfOpand != 2:
                expression = " ".join(self.mark_parentheses(exp, numberOfOpand))
            else:
                expression = " ".join(exp)

            if self.has_duplicate(set, expression):
                print("有重复的啦啦啦啦啦")
                m = m + 1
            else:
                expre = Expression(expression)
                set.append(expre)
        print("----" + str(m))
        if m != 0:
            config.numofexp = m
            setnew = self.generate(config)
            set.extend(setnew)
        if config.get_answer():
            wnum = Answer.answer_one(set)
            if wnum > 0:
                print("jinlaile")
                print("-----------" + str(wnum) + "-----------")
                config.numofexp = wnum
                set1 = self.generate(config)
                set.extend(set1)
        return set

    # 判重逻辑
    def has_duplicate(self, set_express, expression):
        for item in set_express:
            if self.is_duplicate(item.get_expression(), expression):
                return True
        return False

    # 判重
    def is_duplicate(self, expression1, expression2):
        # expression1 = "5 x 4 + ( 2 + 3 )"
        # expression2 = "2 + 3 + 5 x 4"
        if Tree.generate_expression(Tree.create(expression1).get_root()) == Tree. \
                generate_expression(Tree.create(expression2).get_root()):
            return True
        else:
            return False

    # 生成括号表达式
    def mark_parentheses(self, exp, numberOfOpand):

        expression = []
        num = numberOfOpand
        if exp:
            length = len(exp)
            print((length / 2))
            left_position = int((random.randint(0, (num // 2))))
            right_position = int((random.randint(left_position + 1, (num // 2) + 1)))
            mark = -1
            for i in range(length):
                if self.is_operation(exp[i]):
                    expression.append(exp[i])
                else:
                    mark = mark + 1
                    if mark == left_position:
                        expression.append(Constants.LEFT_PARENTHESES)
                        expression.append(exp[i])
                    elif mark == right_position:
                        expression.append(exp[i])
                        expression.append(Constants.RIGHT_PARENTHESES)
                    else:
                        expression.append(exp[i])
        if expression[0] == "(" and expression[-1] == ")":
            expressions = self.mark_parentheses(exp, numberOfOpand)
            return expressions
        return expression

    # 判断是否为运算符
    def is_operation(self, item):
        return {
            '+': True,
            '-': True,
            'x': True,
            '÷': True
        }.get(item, False)

    # 是否生成分数随机判断
    def random_flag(self, flag):
        return bool(random.getrandbits(1)) if flag else False

    # 生成操作数
    def generator_oprand(self, is_fraction, _range):
        return self.generate_an_fraction(_range) if is_fraction else str(random.randint(0, _range))

    # 生成分数
    def generate_an_fraction(self, _range):
        denominator = int(random.randint(2, _range + 1))
        numerator = random.randint(1, denominator)
        while denominator == numerator:
            denominator = random.randint(2, _range + 1)
            numerator = random.randint(1, denominator)
        left_Integer = random.randint(0, 1)
        # 是否生成带分数的随机标识
        max_multiple = self.gcd(denominator, numerator)
        denominator = int(denominator) // int(max_multiple)
        numerator = int(numerator) // int(max_multiple)
        fraction = ""
        if left_Integer == 0:
            fraction = str(numerator) + Constants.VIRGULE + str(denominator)
        else:
            fraction = str(left_Integer) + Constants.SINGLE_QUOTE + str(numerator) + Constants.VIRGULE + str(
                denominator)
        return fraction

    # 求得分子分母最大公约数
    def gcd(self, demo, nume):
        if nume == 0:
            return demo
        r = demo % nume
        return self.gcd(nume, r)

    # 随机取得一个+ - * ÷运算符
    def pick_an_operation(self, operators, *args):
        if args:
            operators.append(args)
        return operators[random.randint(0, len(operators)) - 1]

    # 得到配置参数要求的运算符集合
    @staticmethod
    def generate_available_operators(hasMultipleAndDivide):
        if hasMultipleAndDivide:
            return [Constants.PLUS, Constants.MINUS, Constants.MULTIPLY, Constants.DIVIDE]
        return [Constants.PLUS, Constants.MINUS]
